/*
 * funcionesYEstructurasRaid.c
 *
 *  Created on: 06/10/2011
 *      Author: utn_so
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "funcionesYEstructurasRaid.h"
#include <pthread.h>

extern int32_t offsetSectorMaximo;
extern nodoDiscos *siguienteDiscoAMandarPedido;

void mensajes(char *nombreDisco, tipoOperacion mensaje, char *inicio, char *fin) {
	switch (mensaje) {
	case inicioRaid:
		printf("RAID en funcionamiento\n");
		break;
	case nuevoPlanificador:
		printf("Se conectó planificador de disco: %s\n", nombreDisco);
		break;
	case sincronizaDisco:
		printf("Se sincronizaron los discos[Hora de inicio: %s, Hora de terminacion: %s]\n", inicio, fin);
		break;
	case seHizoWrite:
		printf("Se realizó un pedido de escritura en los discos\n");
		break;
	case seHizoRead:
		printf("Se hizo una lectura del disco: %s\n", nombreDisco);
		break;
	default:
		printf("Opción erronea");
		break;
	}
}

/* fuera de uso
void agregarSector(pedido ped, nodoDisco **list) {
	nodoDisco *aux;
	nodoDisco *nuevo = malloc(sizeof(nodoDisco));
	nuevo->ped = ped;
	nuevo->sig = NULL;
	if (*list == NULL) {
		*list = nuevo;
	} else {
		aux = *list;
		while (aux->sig != NULL) {
			aux = aux->sig;

		}
		aux->sig = nuevo;
	}
}*/

void agregarDisco(nodoDiscos **losDiscos, int32_t socketDisco, char *nombreDisco) {
	nodoDiscos *aux = malloc(sizeof(nodoDiscos));
	aux->pedidos = collection_queue_create();
	aux->idDisco = socketDisco;
	//aux->cantidadPedidos = 0;
	//pthread_mutex_init(&aux->mutexDisco,NULL);
	aux->nombreDisco = malloc(strlen(nombreDisco)+1);
	strcpy(aux->nombreDisco, nombreDisco);
	sem_init(&(aux->pedidos->semaforoPedidos), 0, 0);
	//verifico q haya discos
	if (*losDiscos == NULL) {
		aux->estadoDisco = sincronizado;
		aux->sig=NULL;
		*losDiscos = aux;
	} else {
		aux->estadoDisco = noSincronizado;
		aux->sig = *losDiscos;
		*losDiscos = aux;
	}
	siguienteDiscoAMandarPedido = *losDiscos;
}
/*
int32_t esDisco(nodoDiscos *losDiscos, char* disco) {
        nodoDiscos *aux;
        aux = losDiscos;
        while (aux->nombreDisco != disco && aux->sig != NULL) {
                aux = aux->sig;
        }
        if (aux->sig == NULL && aux->nombreDisco != disco) {
                return esUnDisco;
        } else {
                return noEsUnDisco;
        }
}*/

int32_t SacarDisco(nodoDiscos **losDiscos, uint32_t disco) {
	nodoDiscos *aux;
	nodoDiscos *discoAnt;
	nodoDiscos *discoPost;
	if (*losDiscos == NULL) {
		printf("Se cayeron todos los discos\n");
		exit(2);
	}

	aux = *losDiscos;
	discoAnt = *losDiscos;
	if((*losDiscos)->idDisco==disco){
		*losDiscos=(*losDiscos)->sig;
		return 0;
	}
	while (aux->idDisco != disco && aux->sig != NULL) {
		discoAnt = aux;
		aux = aux->sig;
		discoPost = aux->sig;
	}
	discoAnt->sig = discoPost;
	if (siguienteDiscoAMandarPedido->idDisco == disco)
		siguienteDiscoAMandarPedido = discoAnt;

	return 0;
}

/* Desc: Devuelve verdadero si el idDisco (socket) esta en la cola
 *
 */
int32_t primerDiscoSincronizado(nodoDiscos **losDiscos){
	nodoDiscos *discoAux;
	nodoDiscos *aux;
	discoAux = *losDiscos;
	while(discoAux->estadoDisco==noSincronizado){
		aux = discoAux->sig;
		discoAux = aux;
	}
	return discoAux->idDisco;
}
/*
uint32_t agregarPedido(nodoDiscos **losDiscos, uint32_t disco, pedido ped) {
	nodoDiscos *aux;
	if (*losDiscos == NULL) {
		perror("No hay discos para agregar el pedido");
		return 1;
	} else {
		aux = *losDiscos;
		while (aux->idDisco != disco && aux->sig != NULL) {
			aux = aux->sig;
		}
		if (aux->sig == NULL && aux->idDisco != disco) {
			//llegaste al final y el disco que buscabas no esta hay problemas se cayo etc
			return -1;
		} else {
			collection_queue_push(aux->pedidos, &ped);
			//agregarSector(ped, &aux->pedidos);
			return 1;
		}
	}
}*/

/* fuera de uso
pedido sacarSector(nodoDisco **list) {
	pedido ped;
	nodoDisco *aux;
	if (*list == NULL) {
		//si entras aca la lista esta vacia
		ped.filesystem = -1;
		return ped;
	} else {
		aux = *list;
		ped = aux->ped;
		*list = aux->sig;
		free(aux);
		return ped;
	}
}*/

/*
pedido sacarPedido(nodoDiscos **losDiscos, uint32_t disco) {
	nodoDiscos *aux;
	pedido ped;
	if (*losDiscos == NULL) {
		// no hay discos conectados o sea se cayo algun disco o hubo algun problema
		ped.socket = -1;
		return ped;
	} else {
		aux = *losDiscos;
		while (aux->idDisco != disco && aux->sig != NULL) {
			aux = aux->sig;
		}
		if (aux->sig == NULL && aux->idDisco != disco) {
			//llegaste al final y el disco que buscabas no esta hay problemas se cayo etc
			ped.socket = -1;
			return ped;
		} else {
			memcpy(&ped, collection_queue_pop(aux->pedidos), sizeof(pedido));
			//ped = sacarSector(&aux->pedidos);
		}
	}
	return ped;
}*/

nodoDiscos discoconMenosPedidos(nodoDiscos *losDiscos) {
	uint32_t MinCantidadPedidos = offsetSectorMaximo;
	//uint32_t cantidadPedidos=0;
	nodoDiscos *disco; //para moverme
	nodoDiscos *aux; //para cambiar de disco
	nodoDiscos *discoConMenosPedidos = NULL;
	disco = losDiscos;

	while (disco != NULL) {
		if (disco->estadoDisco == sincronizado) {
			if (disco->pedidos->elements_count <= MinCantidadPedidos) {
				MinCantidadPedidos = disco->pedidos->elements_count;
				discoConMenosPedidos = disco;
			}
		}
		aux = disco->sig;
		disco = aux;
	}
	return *discoConMenosPedidos;
}

//funcion para poner pedidos en todos los discos
void ponerPedidoEnDiscos(pedido *pedido, nodoDiscos **losDiscos) {
	nodoDiscos *disco;
	nodoDiscos *aux;
	disco = *losDiscos;
	while (disco != NULL) {
		if (disco->estadoDisco == sincronizado)
			collection_queue_push(disco->pedidos, pedido);
			sem_post(&disco->pedidos->semaforoPedidos);
		aux = disco->sig;
		disco = aux;
	}
}

